import crypto from 'crypto';
Meteor.methods({
  //判断是否允许soam自动登录，“Y”为允许，“N”为不允许
  judgeSoamAutoLogin() {
    const envValue = process.env.OAUTH2_IS_AUTO_LOGIN_SOAM;
    return envValue;
  },

  //判断是否隐藏除soam按钮之外的组件，“Y”为允许，“N”为不允许
  judgeHideOtherComponents() {
    let envValue = '';
    envValue = process.env.OAUTH2_IS_HIDE_OTHER_COMPONENTS;
    return envValue;
  },

  //获取Soam环境变量
  getSoamProEnv() {
    const envValue = {};
    envValue.isSoamEnabled = process.env.OAUTH2_SOAM_ENABLED;
    envValue.redirect_uri = process.env.OAUTH2_REDIRECT_URI_SOAM;
    envValue.authorize_uri =
      process.env.OAUTH2_TOKEN_SERVER_URL_SOAM +
      process.env.OAUTH2_AUTH_ENDPOINT_SOAM;
    envValue.client_id = process.env.OAUTH2_CLIENT_ID_SOAM;
    envValue.login_style = process.env.OAUTH2_LOGIN_STYLE_SOAM;
    return envValue;
  },

  //模拟授权登录soam
  loginWithSoam(inputParams) {
    check(inputParams, Object);
    const response = getSoamTokenResponse(inputParams.code);
    const identity = getSoamIdentity(response.access_token);
    const expiresAt = +new Date() + 1000 * parseInt(response.expires_in, 10);

    //先判断是否允许新用户注册
    if (Settings.findOne({ disableRegistration: true })) {
      const userTemp = Meteor.users.findOne({
        username: identity.CMBCOANAME,
      });
      if (!userTemp) {
        //获取soam登出信息
        const envValue = {};
        let soamLogoutUrl =
          process.env.OAUTH2_TOKEN_SERVER_URL_SOAM +
          process.env.OAUTH2_LOGOUT_ENDPOINT_SOAM;
        soamLogoutUrl += `?response_type=code&client_id=${process.env.OAUTH2_CLIENT_ID_SOAM}&redirect_uri=${process.env.ROOT_URL}/soam`;
        envValue.soamLogoutUrl = soamLogoutUrl;
        envValue.isAutoLoginSoam = process.env.OAUTH2_IS_AUTO_LOGIN_SOAM;
        envValue.disableRegistration = true;
        return envValue;
      }
    }

    try {
      const user = Accounts.updateOrCreateUserFromExternalService(
        'soam',
        {
          id: `${identity.USERSN}`,
          accessToken: response.access_token,
          refreshToken: response.refresh_token,
          username: identity.CMBCOANAME,
          fullname: identity.SN,
          email: identity.MAIL,
          expiresAt,
        },
        {
          profile: {
            fullname: identity.SN,
          },
        },
      );
      //更新当前user表的resume字段
      const hashedToken = Random.secret();
      const when = new Date();
      //加密hashedToken
      const encryptHashedToken = function(loginToken) {
        const hash = crypto.createHash('sha256');
        hash.update(loginToken);
        return hash.digest('base64');
      };

      //查看localStorage的token是不是在resume的里面是不是第一次登陆项目，若是直接返回浏览器对象下面的local token登陆，否则新建一个token登陆
      const insertedUserIndex = Accounts.users.findOne(user.userId);
      let insertedUserIndexTokenArr = null;
      if (insertedUserIndex.services.resume) {
        insertedUserIndexTokenArr =
          insertedUserIndex.services.resume.loginTokens;
        let flag = false;
        if (inputParams.localToken)
          insertedUserIndexTokenArr.forEach((item, index) => {
            if (
              item.hashedToken === encryptHashedToken(inputParams.localToken)
            ) {
              //先查看localToken是否过期
              if (new Date() >= inputParams.localTokenExpires) {
                //删除当前过期token
                Accounts.users.update(user.userId, {
                  $pull: {
                    'services.resume.loginTokens': item,
                  },
                });
              } else {
                flag = true;
              }
            }
          });
        if (flag) {
          return inputParams.localToken;
        }
      }

      Accounts.users.update(
        {
          _id: user.userId,
        },
        {
          $addToSet: {
            'services.resume.loginTokens': {
              hashedToken: encryptHashedToken(hashedToken),
              when,
            },
          },
        },
      );
      return hashedToken;
    } catch (e) {
      console.log(e);
    }
  },

  //获取Moa环境变量
  getMoaProccessEnv() {
    const envValue = {};
    envValue.redirect_uri = process.env.OAUTH2_REDIRECT_URI_MOA;
    envValue.login_style = process.env.OAUTH2_LOGIN_STYLE_MOA;
    return envValue;
  },

  //模拟授权登录moa
  loginWithMoa(inputParams) {
    check(inputParams, Object);
    const response = getTokenResponse(inputParams.code);
    const identity = getIdentity(response.accessToken);
    const expiresAt = +new Date() + 1000 * parseInt(response.expiresIn, 10);

    //先判断是否允许新用户注册
    if (Settings.findOne({ disableRegistration: true })) {
      const userTemp = Meteor.users.findOne({
        username: identity.userId,
      });
      if (!userTemp) {
        return 'disableRegistration';
      }
    }

    try {
      const user = Accounts.updateOrCreateUserFromExternalService(
        'moa',
        {
          id: `${identity.userNumber}`,
          accessToken: response.accessToken,
          refreshToken: response.refreshToken,
          username: identity.userId,
          fullname: identity.userName,
          email: identity.userEmail,
          expiresAt,
        },
        {
          profile: {
            fullname: identity.userName,
          },
        },
      );

      //更新当前user表的resume字段
      const hashedToken = Random.secret();
      const when = new Date();
      //加密hashedToken
      const encryptHashedToken = function(loginToken) {
        const hash = crypto.createHash('sha256');
        hash.update(loginToken);
        return hash.digest('base64');
      };

      //查看localStorage的token是不是在resume的里面是不是第一次登陆项目，若是直接返回浏览器对象下面的local token登陆，否则新建一个token登陆
      const insertedUserIndex = Accounts.users.findOne(user.userId);
      let insertedUserIndexTokenArr = null;
      if (insertedUserIndex.services.resume) {
        insertedUserIndexTokenArr =
          insertedUserIndex.services.resume.loginTokens;
        let flag = false;
        if (inputParams.localToken)
          insertedUserIndexTokenArr.forEach((item, index) => {
            if (
              item.hashedToken === encryptHashedToken(inputParams.localToken)
            ) {
              //先查看localToken是否过期
              if (new Date() >= inputParams.localTokenExpires) {
                //删除当前过期token
                Accounts.users.update(user.userId, {
                  $pull: {
                    'services.resume.loginTokens': item,
                  },
                });
              } else {
                flag = true;
              }
            }
          });
        if (flag) {
          return inputParams.localToken;
        }
      }

      Accounts.users.update(
        {
          _id: user.userId,
        },
        {
          $addToSet: {
            'services.resume.loginTokens': {
              hashedToken: encryptHashedToken(hashedToken),
              when,
            },
          },
        },
      );
      return hashedToken;
    } catch (e) {
      console.log(e);
    }
  },
});

let userAgent = 'Meteor';
if (Meteor.release) {
  userAgent += `/${Meteor.release}`;
}

//getSoamTokenByCode
function getSoamTokenResponse(code) {
  //check(code, String);
  let response;
  const serverTokenEndpoint =
    process.env.OAUTH2_SERVER_URL_SOAM + process.env.OAUTH2_TOKEN_ENDPOINT_SOAM;
  try {
    const postOptions = {
      headers: {
        Accept: 'application/json',
        'User-Agent': userAgent,
      },
      params: {
        code,
        client_id: process.env.OAUTH2_CLIENT_ID_SOAM,
        client_secret: Soam.OAuthForServer.openSecret(
          process.env.OAUTH2_SECRET_SOAM,
        ),
        redirect_uri: process.env.OAUTH2_REDIRECT_URI_SOAM,
        grant_type: 'authorization_code',
      },
    };
    // if (httpCa) {
    //   postOptions['npmRequestOptions'] = { ca: httpCa };
    // }
    response = HTTP.post(serverTokenEndpoint, postOptions);
  } catch (err) {
    throw Object.assign(
      new Error(`Failed to complete OAuth handshake with Soam. ${err.message}`),
      { response: err.response },
    );
  }
  // result.headers["content-type"] is 'text/plain;charset=UTF-8', so
  // the http package doesn't automatically populate result.data
  response.data = JSON.parse(response.content);

  if (response.data.error) {
    // if the http response was a json object with an error attribute
    throw new Error(
      `Failed to complete OAuth handshake with Soam. ${response.data.error}`,
    );
  } else {
    return response.data;
  }
}

//getSoamUserInfoByToken
const getSoamIdentity = (accessToken, refreshToken) => {
  const serverUserinfoEndpoint =
    process.env.OAUTH2_SERVER_URL_SOAM +
    process.env.OAUTH2_USERINFO_ENDPOINT_SOAM;
  let response;
  try {
    const postOptions = {
      headers: {
        Accept: 'application/json',
        'User-Agent': userAgent,
      },
      params: {
        access_token: accessToken,
        refresh_token: refreshToken,
      },
    };
    response = HTTP.post(serverUserinfoEndpoint, postOptions);
  } catch (err) {
    throw Object.assign(
      new Error(`Failed to fetch identity from Soam. ${err.message}`),
      { response: err.response },
    );
  }

  response.data = JSON.parse(response.content);
  if (response.data.error) {
    // if the http response was a json object with an error attribute
    throw new Error(
      `Failed to fetch identity from Soam. ${response.data.error}`,
    );
  } else {
    return response.data;
  }
};

//getMoaTokenByCode
function getTokenResponse(code) {
  //check(code, String);
  let response;
  const serverTokenEndpoint =
    process.env.OAUTH2_SERVER_URL_MOA + process.env.OAUTH2_TOKEN_ENDPOINT_MOA;
  try {
    const postOptions = {
      headers: {
        Accept: 'application/json',
        'User-Agent': userAgent,
      },
      params: {
        code,
        client_id: process.env.OAUTH2_CLIENT_ID_MOA,
        client_secret: Moa.OAuthForServer.openSecret(
          process.env.OAUTH2_SECRET_MOA,
        ),
        redirect_uri: process.env.OAUTH2_REDIRECT_URI_MOA,
        grant_type: 'authorization_code',
      },
    };
    response = HTTP.post(serverTokenEndpoint, postOptions);
  } catch (err) {
    throw Object.assign(
      new Error(`Failed to complete OAuth handshake with Moa. ${err.message}`),
      { response: err.response },
    );
  }
  // result.headers["content-type"] is 'text/plain;charset=UTF-8', so
  // the http package doesn't automatically populate result.data
  response.data = JSON.parse(response.content);
  if (response.data.error) {
    // if the http response was a json object with an error attribute
    throw new Error(
      `Failed to complete OAuth handshake with Moa. ${response.data.error}`,
    );
  } else {
    return response.data;
  }
}

//getMoaUserInfoByToken
function getIdentity(accessToken) {
  //check(accessToken, String);
  const serverUserinfoEndpoint =
    process.env.OAUTH2_SERVER_URL_MOA +
    process.env.OAUTH2_USERINFO_ENDPOINT_MOA;
  let response;
  try {
    // const getOptions = {
    //   headers: {
    //     'User-Agent': userAgent,
    //   },
    //   params: {
    //     accesstoken: accessToken,
    //   },
    // };
    // response = HTTP.get(serverUserinfoEndpoint, getOptions);
    const postOptions = {
      headers: {
        Accept: 'application/json',
        'User-Agent': userAgent,
      },
      params: {
        accesstoken: accessToken,
      },
    };
    response = HTTP.post(serverUserinfoEndpoint, postOptions);
  } catch (err) {
    throw Object.assign(
      new Error(`Failed to fetch identity from Moa. ${err.message}`),
      { response: err.response },
    );
  }
  response.data = JSON.parse(response.content);
  if (response.data.error) {
    // if the http response was a json object with an error attribute
    throw new Error(
      `Failed to fetch identity from Soam. ${response.data.error}`,
    );
  } else {
    return response.data;
  }
}
